package com.etone.smartAudit.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.etone.smartAudit.config.EGCCConfig;
import com.etone.smartAudit.dto.egcc.*;
import com.etone.smartAudit.error.CustomParameterizedException;
import com.etone.smartAudit.utils.RSANewUtils;
import com.etone.smartAudit.vo.egcc.SendMsgVO;
import com.etone.smartAudit.vo.egcc.TokenVO;
import com.etone.smartAudit.vo.egcc.UnitodoDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.net.URLDecoder;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;


/***
 * E掌通
 */
@Slf4j
@Service
public class EGCCMService {

    @Autowired
    private EGCCConfig config;

    @Autowired
    private RestTemplateRequest request;

    @Value("${egc.host_url:http://10.252.225.35:9081/gmccservice}")
    private String hostUrl;

    /***
     * 请求地址
     */
    @Value("${egc.5G_MSG_URL:http://10.252.225.35:18088}")
    private String msgHostUrl;

    @Value("${egc.h5_host_url:http://120.198.246.137:18088}")
    private String h5Host;

    @Value("${egc.pc_url:http://120.198.246.137:18088}")
    private String pcUrl;

    /***
     * h5请求主入口
     */
    @Value("${egc.h5_main:smartAuditH5}")
    private String h5Main;

    @Value("${egc.use_h5_url:smartAuditH5}")
    private String userH5url;

    @Autowired
    private RedisUtil redisUtil;

    /***
     * 2.1.4	获取访问令牌
     * 接口编号	moa_003
     * 接口地址	/accesstoken/get
     * 接口名称	获取访问令牌
     * 功能描述	提供访问令牌的获取功能，作为调用的凭证。
     * 功能提供者	平台
     * 功能调用者	应用
     * 元素名称	约束	类型	长度	描述	取值说明
     * corpId	1	String	v20	开发者编号	由平台创建开发者时生成
     * appSecret	1	String	v30	应用密钥	由平台创建应用时生成
     * @return
     */
    public TokenVO getToken() {

        String url = hostUrl + "/accesstoken/get";
        EGCCConfig eConfig = config.init();
        JSONObject param = JSON.parseObject(JSON.toJSONString(eConfig));
        log.info("请求参数为" + param.toJSONString());
        AtomicReference<TokenVO> vo = new AtomicReference<>();
        request.postRequestBody(param, url, result -> {
            vo.set(JSON.parseObject(result, TokenVO.class));
            log.info("请求返回数据为:" + result);
            log.info("==========");
        });
        return vo.get();
    }

    /***
     * 验证登录令牌
     * @param dto
     * @return
     */
    public VerifyUserVo validateLoginToken(VerifyTokenDTO dto) {
        String url = hostUrl + "/logintoken/validate";
        EGCCConfig eConfig = config.init();
        eConfig.setToken(getToken().getData());
//        eConfig.setToken("NzU0NzhmMGQtYmM2NC00ODVlLTk1MTktYWRjMDQ3YTdlOWMyMTY0ODY5Nzc2NzkxNzAwMQ");
        JSONObject param = JSON.parseObject(JSON.toJSONString(eConfig));
        param.put("loginToken", dto.getLoginToken());
        log.info(param.toJSONString());
        AtomicReference<VerifyUserVo> userInfo = new AtomicReference<>();
        request.postRequestBody(param, url, result -> {
            //{"msg":"成功","code":"0","data":{"uid":"hujungang","mobile":"13760676142","region":"省公司"},
            // "appId":"NSgJYJsC","time":"20220331142957","sid":"5e3f28be4f004b90a1add6c3f85ede4c"}
            if(StrUtil.isNotEmpty(result)){
                JSONObject obj = JSON.parseObject(result);
                String code = obj.getString("code");
                if("0".equals(code)){
                    //校验成功
                    VerifyUserVo vo = JSON.parseObject(obj.getJSONObject("data").toJSONString(),VerifyUserVo.class);
                    userInfo.set(vo);
                    //使用redis缓存登录结果
                }
            }
            log.debug("请求url:{}",url);
            log.info("验证登录token:" + result);
            //验证成功执行登录  验证信息中有portal信息
        });

        return userInfo.get();
    }


    /**
     * 2.1.5	推送统一待办消息
     * 接口编号	sm_004
     * 接口地址	/msg/push/unitedtodo
     * 接口名称	推送统一待办消息
     * 功能描述	提供统一待办（包括待办、待阅两类）消息的推送功能，用于将应用的数据同步到平台，并将消息通知给用户。
     * 功能提供者	平台
     * 功能调用者	应用
     */
    public void sendMsg() {
        String url = hostUrl + "/msg/push/unitedtodo";
        //发送消息通知
        UnitodoDTO dto = new UnitodoDTO();
        BeanUtils.copyProperties(config.init(), dto);
        //获取token
        String token = getTokenValue();
        dto.setToken(token);

        /**
         * 请求参数
         * bid	1	String	v20	业务编号	源系统唯一
         * btype	1	String	v4	业务类型	 见：字典定义（业务类型）
         * btitle	1	String	v30	业务标题	用户统一待办列表展示
         * launcher	1	String	v20	发起人uid	portal账号
         * launchTime	1	String	14	发起时间	格式为：yyymmddhh24miss；消息时间也取自此信息
         * processor	1	String	v20	处理人uid	portal账号
         * baction	?	String	v2	业务操作	见：字典定义（业务操作）；默认为新增操作，修改和删除操作只对待办、待阅业务操作有效且业务系统需要做好严格的业务逻辑控制（可能会造成消息与待办、待阅列表显示不一致）；
         * bsubType	?	String	v20	业务子类型	公司发文、部门发文、草稿文件等；
         * OA系统不能为空；
         * bopinion	?	String	v200	发起人意见
         * bpriority	?	Integer		业务优先级	大于等于0的整数，数值越大优先级越高；默认为0；
         * mtitle	?	String	v30	消息标题	用于消息标题展示，如果为空则取业务标题
         * mcontent	1	String	v300	消息内容	用于消息内容展示
         * murl	1	String	v200	消息跳转地址	http打头的表示html5地址；否则表示为原生应用地址；
         */
//        dto.setBid();
//        dto.setBtype();
//        dto.setBtitle();
//        dto.setLauncher();
//        dto.setLaunchTime();
//        dto.setProcessor();
//        dto.setBaction();
//        dto.setBsubType();
//        dto.setBopinion();
//        dto.setBpriority();
//        dto.setMtitle();
//        dto.setMcontent();
//        dto.setMurl();
        JSONObject param = JSON.parseObject(JSON.toJSONString(dto));
        request.postRequestBody(param, url, result -> {
            SendMsgVO vo = JSON.parseObject(result, SendMsgVO.class);
        });

    }

    /***
     * 获取审计h5文档
     * @return
     */
    public String getCerH5Url(String key) {
        return h5Host + "/" + h5Main + "?loginKey=" + key;
//        return h5Host;
    }

    /***
     * 获取pc端审计审批链接地址
     * @param key
     * @return
     */
    public String getPcUrl(String key) {
        if ("true".equals(userH5url)) {
            String miniUrl = toMiniProgramAddress(getCerH5Url(RandomUtil.randomNumbers(32)));
//            return getCerH5Url(key);
            return miniUrl;
        }
        return pcUrl + "/loginProcess?loginKey=" + key;
    }

    /***
     * 获取发送内容
     * @param code
     * @return
     */
    private String getContent(MsgDTO msgDTO) {
        String miniUrl = toMiniProgramAddress(getCerH5Url(msgDTO.getLoginKey()));
//        String miniUrl = "https://hfx.net/i/lwcapB";
//        String content = String.format("您有审计单待处理，请登录:%s,\t\n登录验证码为:%s", miniUrl, code);
        msgDTO.setUrl(miniUrl);
        String content = formatContent(msgDTO);
        return content;
    }

    /***
     * 格式化内容
     * @return
     */
    private String formatContent(MsgDTO dto) {
        //执行人短信
        String content = "您好！%s 的审计%s需您处理。请登录  %s 根据实际情况进行回复。验证码为%s -----广东移动内审部";
//        0- 执行人信息  1-抄送信息  2-反馈信息
        if (dto.getMsgType() == 1) {
            //抄送短信
            content = "您好！ 您的同事正在协助进行 %s 的审计%s处理工作。可登录 %s 进行查阅。验证码为：%s -----广东移动内审部";
        } else if (dto.getMsgType() == 2) {
            //反馈短信
            content = "您好！%s 的审计需求 %s 需咨询您意见。请登录  %s  根据实际情况进行回复。验证码为：%s -----广东移动内审部";
        }
        String realContent = String.format(content, dto.getItemName(), getTypeName(dto.getType()), dto.getUrl(), dto.getCode());
        return realContent;
    }

    /***
     * 获取单类型名称
     * @param type
     * @return
     */
    private String getTypeName(Integer type) {
        if (type == 1) {
            return "确认单";
        }
        return "需求单";
    }

    /***
     * 异步调用
     * E掌通短信地址
     * 3.1.	E掌通侧提供接口
     * 3.1.1.	短信下行接口
     * 3.1.1.1.	核心功能点
     * 1.移动办公平台提供接口提交数据，接口完成发送。
     * 2.安全问题可以做ip白名单校验。
     * 请求地址：
     * 生产：https://120.198.246.146:8081/messageBase/smsDownlink
     * 测试(内网)：http://10.252.225.35:18088/messageBase/smsDownlink
     * 新地址/emessage/sms
     */
    @Async
    public void sendEmsg(String mobile, MsgDTO msgDTO) {
        try {
            String url = msgHostUrl + "/messageBase/smsDownlink";
            log.info("请求地址为:" + url);
            String content = getContent(msgDTO);
//        String miniUrl = toMiniProgramAddress(sendUrl);
//        content = content + "，访问地址:" + miniUrl;
//        参数
//        3.1.1.2.	http head请求数据
//        名称	必选	类型	长度	说明
//        authKey	否	String		验签key（由应用侧提供）
//        sign	否	String		签名，由调用方生成，详细见4.加签验签

//        ciphertext	密文	True	32	String	参数（json格式）使用RSA加密
//        timestamp	用户id	True	32	Long	5分钟内请求有效
//        sign	操作功能	True	32	String	参数（json格式）加密前的md5值


//        参数ciphertext解密参数定义：
//        名称	必选	类型	长度	说明
//        appId	是	String		应用id（联调时彩讯提供）
//        mobileNumber	是	String		接收短信的手机号码
//        smsContent	是	string		下行的短信内容，其中url要先转成短信小程序的地址
//        sid	是	string		请求流水号，需要保证唯一
//        time	是	string		请求时间，格式为：yyymmddhh24miss
            config.init();
//        Map<String, String> map = new TreeMap<>();
            JSONObject map = new JSONObject();
            map.put("appId", config.getAppId());
            map.put("mobileNumber", mobile);
            map.put("smsContent", content);
            map.put("sid", config.getSid());
            map.put("time", DateUtil.formatDateTime(new Date()));

            JSONObject param = new JSONObject();
            param.put("ciphertext", RSAData(map));
            param.put("timestamp", System.currentTimeMillis() + "");
            param.put("sign", sign(map));

            Map<String, String> head = getHeader(map);
//            head.put("token", "OGE2ZDQ1M2ItNjQxNS00NzZjLWFlY2YtNzIzMzhhZGVjOWZlMTYyNzQ1ODc0NDI2OTAwMQ");
            log.info("请求参数为:" + param);
            log.info("请求header为:" + head);
            //执行post请求
            request.postRequestBody(param, url, head, result -> {
//            3.1.1.4.	响应数据
//            名称	必选	类型	长度	说明
//            status	是	Int		1-成功，0-错误
//            errMsg	是	String		具体错误信息，如果status=1，则不返回改字段
//            sid	是	string		将请求流水号原样返回
                JSONObject object = JSON.parseObject(result);
                String status = object.getString("status");
                log.info(result);
                if ("1".equals(status)) {
                    //发送短信成功
                    log.info("小程序短信发送成功");
                } else {
                    log.error(result);
                    throw new CustomParameterizedException("小程序短信发送失败");
                }
            });
        } catch (Exception e) {
            log.error("发送短信失败,", e);
        }
    }


    /***
     * 获取请求头数据
     * @param map
     * @return
     */
    private Map<String, String> getHeader(JSONObject map) {
        Map<String, String> head = new HashMap<>();
        head.put("authKey", config.getAuthKey());
        head.put("sign", sign(map));
        return head;
    }

    /***
     * 链接转小程序地址
     * 3.1.2.	H5 地址转短信小程序地址接口
     * 3.1.2.1.	核心功能点
     * 1.将H5地址转换成短信小程序地址，从而拼接到短信中。
     *
     * 请求地址：
     * 生产：https://120.198.246.146:8081/messageBase/reqConvertShortUrl
     * 测试(内网)：http://10.252.225.35:18088/messageBase/reqConvertShortUrl
     * @return
     */
    public String toMiniProgramAddress(String url) {
//        名称	必选	类型	长度	说明
//        ciphertext	是	String		Json数据加密参数，根据公钥进行加密,公钥到时候联调时提供，ciphertext解密后JSON示例
//
//        {
//            "appId": "5cfb0dea46e532c7d27eec7910c81949",
//                "url": "http://www.baidu.com"
//        }
//        appId：String类型，应用id（联调时应用侧提供）
//        url：String 类型，应用系统需要转换的url
//        sign	是	String		未加密json数据进行md5转码
//        timestamp	是	String		时间戳，可以根据当前时间获取
        String host = msgHostUrl + "/messageBase/reqConvertShortUrl";
        //获取请求内容
        JSONObject map = new JSONObject();
        map.put("appId", config.getAppId());
        map.put("url", url);

        //获取请求头
        Map<String, String> header = getHeader(map);

        JSONObject param = new JSONObject();
        param.put("ciphertext", RSAData(map));
        param.put("sign", sign(map));
        param.put("timestamp", System.currentTimeMillis());
        //执行post请求
        log.info("toMiniProgramAddress请求数据为:" + param.toJSONString());
        AtomicReference<String> miniUrl = new AtomicReference<>("");
        request.postRequestBody(param, host, result -> {
//            名称	必选	类型	父节点	长度	说明
//            status	是	String			SUCCESS 代表成功
//            msg	是	String			成功
//            content	是	JsonArray			数组：内容
//            destUrl	是	String	content		根据H5 url生成的短链

//            {
//                "status": "1",
//                    "msg": "成功",
//                    "content": [
//                {
//                    "destUrl": "https://hfx.net/i/74KfQN"
//                }
//	        ]
//            }
            JSONObject object = JSON.parseObject(result);
            String status = object.getString("status");
            if ("1".equals(status)) {
                //请求成功
                JSONArray array = object.getJSONArray("content");
                try {
                    miniUrl.set(array.getJSONObject(0).getString("destUrl"));
                } catch (Exception e) {
                    log.error("获取不到转换地址", e);
                }
            } else {
                throw new CustomParameterizedException("转换链接失败");
            }
            log.info(result);
        });
        return miniUrl.get();
    }


    /***
     * 校验手机号是否存在
     * 3.2.1.	用户验证接口
     * 3.2.1.1.	核心功能点
     * 1.e掌通侧调用该接口，通过传递手机号码给应用侧，验证用户是否存在，包括移动员工和非员工。
     */
    public VerifyMobileVO verifyMobile(VerifyDTO dto) {
//        appId	是	String		应用id（联调时应用侧提供）
//        mobileNumber	是	String		接收短信的手机号码
//        sid	是	string		请求流水号，需要保证唯一
        //判断appId是否正确
        VerifyMobileVO vo = new VerifyMobileVO();
        vo.setStatus(1);
        if (!config.getAppId().equals(dto.getAppId())) {
//            throw new CustomParameterizedException("appid不正确");
            vo.setErrMsg("appid不正确");
            vo.setStatus(0);
        }

        if (StrUtil.isEmpty(dto.getMobileNumber())) {
            vo.setErrMsg("手机号码不能为空");
            vo.setStatus(0);
        }
        vo.setSid(dto.getSid());
//        JSONObject param = new JSONObject();
//        param.put("appId", config.getAppId());
////        param.put("mobileNumber", mobile);
//        param.put("sid", config.getSid());
        return vo;

    }

    /***
     * 获取token值
     * @return
     */
    private String getTokenValue() {
        return null;
    }


    /***
     * 参数签名
     * @return
     */
    private String sign(JSONObject map) {
        String json = map.toJSONString();
        return DigestUtils.md5Hex(json);
    }

    /***
     * RSA加密数据
     * @return
     *
     */
    private String RSAData(JSONObject map) {
        String json = map.toJSONString();
        log.info("未加密的数据为" + json);
        return RSANewUtils.encryptByPublic(json, config.getPublicKey());
    }


    /***
     * 跳转到自己的h5页面
     * @param dto
     * @return
     */
    public String toOwnerPage(ToPageDTO dto) {
        String url = h5Host + "/" + h5Main;
        return url;
    }

    public static void main(String[] args) throws Exception {
//        String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7OLxKa6taQxK1PCFIn1N/UFwx1rCGKQ0oN1T2H9UnBWVNYVhUJHqMBZwfBs6kNZwSn3uDkLnNgA94NAzwCjzjj6cBta7NWLZTVZTBfP2bw2ujPmVClMwK/sj5KlTRRlUoHZ6tdvcK85iovaA6E3fYmO/fJyIQ13KbgEFyd2HUGQIDAQAB";
//        RSA rsa = new RSA(null, publicKey);
//        //加密
//        byte[] encrypted = rsa.encrypt(StrUtil.bytes("我是一段测试aaaa", CharsetUtil.CHARSET_UTF_8), KeyType.PublicKey);
//        String str = new BASE64Encoder().encode(encrypted);
//        Map<String, String> map = new HashMap<>();
//        map.put("apid", "fewfewfewf");
//        map.put("fff", "fewfewfwefew");
////        String stt = sign(map);
//        System.out.println(str);
//        System.out.println(stt);
        String url = "loginKey&loginNo=Fri%20Aug%2020%2014:24:58%20CST%202021hujungang&gdmoaclientversion=1.4.5.4&gdmoasignature=C7BE9FEB8B65B33C45F8D40165D018FE&gdmoatoken=bebc0c1e4b834b53b8843336660f6664&gdmoatimestamp=1629440727762";
        System.out.println(URLDecoder.decode(url, "utf-8"));
    }
}
